﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TekaMUD.Engine.Framework;
using TekaMUD.Engine.IO;

namespace TekaMUD.Engine
{
	/// <summary>
	/// Manages world weather and time.
	/// </summary>
	public class Environment
	{
		public const int WINTER_SUN_RISE_HOUR = 7;
		public const int WINTER_SUN_SET_HOUR = 17;
		public const int SPRING_SUN_RISE_HOUR = 6;
		public const int SPRING_SUN_SET_HOUR = 18;
		public const int SUMMER_SUN_RISE_HOUR = 5;
		public const int SUMMER_SUN_SET_HOUR = 19;
		public const int FALL_SUN_RISE_HOUR = 6;
		public const int FALL_SUN_SET_HOUR = 18;

		public const int MIN_WEATHER_DURATION = 6;
		public const int MAX_WEATHER_DURATION = 15;

		public const int MAX_WIND_SPEED_SUNNY = 6;
		public const int MAX_WIND_SPEED_OTHER = 10;

		private static double[,][] weather_table = new double[,][]
		{
			{ new double[] {0.1, 0.9, 0, 0}, new double[] {0.1, 0.3, 0.3, 0.3}, new double[]{0.1, 0.3, 0.6, 0}, new double[]{0, 0.5, 0, 0.5} },	
			{ new double[] {0.8, 0.2, 0, 0}, new double[] {0.7, 0.1, 0.2, 0}, new double[] {0, 0.6, 0.4, 0}, new double[] {0, 1, 0, 0}         },	/* spring */
			{ new double[] {0.9, 0.1, 0, 0}, new double[] {0.8, 0.1, 0.1, 0}, new double[] {0, 0.5, 0.5, 0}, new double[] {0, 1, 0, 0}         },	/* summer */
			{ new double[] {0.4, 0.6, 0, 0}, new double[] {0.2, 0.4, 0.35, 0.05}, new double[] {0, 0.3, 0.7, 0}, new double[] {0, 0.8, 0, 0.2} }	/* fall */
		};

		private static string[,] changes = new string[,]
		{
			{null, "The sky is getting cloudy\n", null, null},
			{"The clouds start to disappear\n", null, "It's raining\n", "It starts snowing\n"},
			{null, "It stops raining\n", null, null},
			{"The sun starts shining", "Snow has stop falling\n", null, null}
		};

		private static void UpdateTime(EnvData env)
		{
			env.WorldClock = env.WorldClock.AddHours(4);

			// Christmas.
			if (env.WorldClock.Day == 25 && env.WorldClock.Month == 12)
				Messenger.Broadcast("Merry christmas!! ho ho ho.. :)\n");

			if (env.WorldClock.Day == 1 && env.WorldClock.Month == 1 && env.WorldClock.Hour == 0)
				Messenger.Broadcast("Happy new year!!!\n");

			if (env.WorldClock.Day == 1)
			{
				switch (env.WorldClock.Month)
				{
					case 1:
						env.CurrentSeason = Season.Winter;
						break;

					case 4:
						env.CurrentSeason = Season.Spring;
						break;

					case 7:
						env.CurrentSeason = Season.Summer;
						break;

					case 11:
						env.CurrentSeason = Season.Fall;
						break;
				}
			}

			switch (env.WorldClock.Hour)
			{
				case 12:
					Messenger.Broadcast("It is now midday.\n");
					break;

				case 0:
					Messenger.Broadcast("It's midnight.\n");
					break;
			}

			switch (env.CurrentSeason)
			{
				case Season.Fall:
					if (env.WorldClock.Hour == FALL_SUN_RISE_HOUR)
						Messenger.Broadcast("The Sun rises in the west.\n");

					if (env.WorldClock.Hour == FALL_SUN_RISE_HOUR)
						Messenger.Broadcast("The Sun sets in the east.\n");
					break;

				case Season.Spring:
					if (env.WorldClock.Hour == SPRING_SUN_RISE_HOUR)
						Messenger.Broadcast("The Sun rises in the west.\n");

					if (env.WorldClock.Hour == SPRING_SUN_RISE_HOUR)
						Messenger.Broadcast("The Sun sets in the east.\n");
					break;

				case Season.Summer:
					if (env.WorldClock.Hour == SUMMER_SUN_RISE_HOUR)
						Messenger.Broadcast("The Sun rises in the west.\n");

					if (env.WorldClock.Hour == SUMMER_SUN_SET_HOUR)
						Messenger.Broadcast("The Sun sets in the east.\n");
					break;

				case Season.Winter:
					if (env.WorldClock.Hour == WINTER_SUN_RISE_HOUR)
						Messenger.Broadcast("The Sun rises in the west.\n");

					if (env.WorldClock.Hour == WINTER_SUN_SET_HOUR)
						Messenger.Broadcast("The Sun sets in the east.\n");
					break;
			}

			return;
		}

		private static void UpdateWeather(EnvData env)
		{
			int max_wind;

			if (--env.WeatherDuration <= 0)
			{
				env.PreviousWeatherType = env.CurrentWeatherType;

				env.CurrentWeatherType = (WeatherType)Randomizer.PickRandomEntry(weather_table[(int)env.CurrentSeason, (int)env.CurrentWeatherType]);

				env.WeatherDuration = Randomizer.GetInteger(MIN_WEATHER_DURATION, MAX_WEATHER_DURATION);

				string changeMsg = changes[(int)env.PreviousWeatherType, (int)env.CurrentWeatherType];

				if (changeMsg != null)
					Messenger.Broadcast(changeMsg);

				/* Calculate the new wind direction	*/
				env.WindDirection = (WindDirection)Randomizer.GetInteger(0, 7);

				/* Calculate the new wind strength	*/
				if (env.CurrentWeatherType == WeatherType.Sunny)
					max_wind = MAX_WIND_SPEED_SUNNY;
				else
					max_wind = MAX_WIND_SPEED_OTHER;

				env.WindStrength = Randomizer.GetInteger(0, max_wind);
			}
			return;
		}

		public static void Update(EnvData env)
		{
			UpdateTime(env);
			UpdateWeather(env);
		}
	}

	public class EnvData
	{

		public WeatherType CurrentWeatherType { get; set; }
		public WeatherType PreviousWeatherType { get; set; }
		public DateTime WorldClock { get; set; }
		public Season CurrentSeason { get; set; }
		public int WeatherDuration { get; set; }
		public WindDirection WindDirection { get; set; }
		public int WindStrength { get; set; }

		public EnvData()
		{
			CurrentWeatherType = WeatherType.Sunny;
			PreviousWeatherType = WeatherType.Sunny;
			WorldClock = new DateTime(1700, 1, 1);
			CurrentSeason = Season.Winter;
			WeatherDuration = 1;
			WindDirection = WindDirection.North;
			WindStrength = 0;
		}

		public string DescribeSeason()
		{
			return CurrentSeason.ToString().ToLower();
		}

		public string DescribeWeather()
		{
			switch (CurrentWeatherType)
			{
				case WeatherType.Cloudy:
					return "it's cloudy";

				case WeatherType.Rainy:
					return "it's raining";

				case WeatherType.Snowing:
					return "it's snowing";
				
				case WeatherType.Sunny:
				default:
					return "the skies are clear of any clouds";
			}
		}

		public string DescribeWind()
		{

			switch (WindStrength)
			{
				case 0:
				default:
					return "The weather is calm.";

				case 1:
				case 2:
				case 3:
					return "There is a gentle brise flowing from the %s.\n\n";


				case 4:
				case 5:
				case 6:
					return string.Format("The wind blows from the {0}.", WindDirection.ToString());


				case 7:
				case 8:
					return string.Format("Stormy winds are coming from the {0}.", WindDirection.ToString());


				case 9:
				case 10:
					return string.Format("A major storm is coming from the {0}.", WindDirection.ToString());


			}
		}
	}

	public enum Season
	{
		Winter,
		Spring,
		Summer,
		Fall,
	}

	public enum WeatherType
	{
		Sunny = 0,
		Cloudy = 1,
		Rainy = 2,
		Snowing = 3,
	}

	public enum WindDirection
	{
		North,
		Northeast,
		East,
		Southeast,
		South,
		Southwest,
		West,
	}
}